package com.camtc.camcenter.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.camtc.camcenter.config.jwt.JwtAuthenticationToken;
import com.camtc.camcenter.util.HttpUtils;
import com.camtc.camcenter.util.JwtTokenUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

/**
 * jwt验证过滤器
 *
 * @author
 * @date
 */
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {

    public JwtLoginFilter(AuthenticationManager authenticationManager) {
        setAuthenticationManager(authenticationManager);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        super.doFilter(req, res, chain);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        // 可以覆写尝试进行登录认证的逻辑，登录成功之后等操作不在方法内
        // 使用此过滤器来触发登录认证的流程，注意登录请求数据格式的问题
        // 此过滤器的用户名密码默认从request.getParameter() 获取，但这种读取方式不能读取到如 application/json 等POST 请求数据，需要把用户名密码的读取逻辑修改为从流中读取，request.getInputStream()
        String body = getBody(request);
        JSONObject jsonObject = JSON.parseObject(body);
        String username = jsonObject.getString("username");
        String password = jsonObject.getString("password");
        if (username == null) {
            username = "";
        }
        if (password == null) {
            password = "";
        }
        username = username.trim();
        JwtAuthenticationToken authRequest = new JwtAuthenticationToken(username, password);
        // 允许子类设置“details”属性
        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        // 存储登录认证信息到上下文
        SecurityContextHolder.getContext().setAuthentication(authResult);
        // 记住服务
        getRememberMeServices().loginSuccess(request, response, authResult);
        // 事件触发器
        if (this.eventPublisher != null) {
            eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
        }
        JwtAuthenticationToken token = new JwtAuthenticationToken(null, null, JwtTokenUtils.generateToken(authResult));
        HttpUtils.write(response, authResult);
    }

    /**
     * 获取请求Body
     *
     * @param request
     * @return
     */
    private String getBody(HttpServletRequest request) {
        StringBuilder stringBuilder = new StringBuilder();
        InputStream in = null;
        BufferedReader bufferedReader = null;
        try {
            in = request.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(in, Charset.forName("UTF-8")));
            String line = "";
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return stringBuilder.toString();
    }
}
